using UnityEngine;

namespace JufGame.CptMod
{
	[System.Serializable]
	/// <summary>
	/// 可观察度：玩家注意到该角色的可能性
	/// </summary>
	public class Observability
	{
		public float ObserValue { get; private set; } = 0;//缓存计算后的可观察值
		public float LastObsTime { get; private set; } = -0.2f;//最后一次被观察到的时间，即上次ObserValue不为0的时候
		public Renderer Renderer => renderer;
		[Tooltip("代表物体外形")]
		[SerializeField] private Renderer renderer;
		[Tooltip("物体可完全看清的最小大小, 更高分辨率的游戏, 该值可以小一些")]
		[SerializeField] private float saturationSize;
		private Vector3[] boundsVertexs;//缓存包围盒8个顶点的数组
		private Plane[] cameraPlanes;//相机视锥体
		public Observability(Renderer renderer, float saturationSize)
		{
			this.renderer = renderer;
			this.saturationSize = saturationSize;
		}
		/// <summary>
		/// 获取可观察值大小(0-1)
		/// </summary>
		/// <returns>当前大小占参考饱和度的百分比</returns>
		public float UpdateObservability(Camera viewCamera)
		{
			cameraPlanes = GeometryUtility.CalculateFrustumPlanes(viewCamera);
			if(GeometryUtility.TestPlanesAABB(cameraPlanes, Renderer.bounds))
			{
				UpdateBoundsVertexs();
				LimitVertexs(viewCamera);
				SortVertexs();
				ObserValue = Mathf.Min(CalculateArea()/saturationSize, 1);
				LastObsTime = Time.time;
			}
			else
			{
				ObserValue = 0;
			}
			return ObserValue;
		}
		#if UNITY_EDITOR
		/// <summary>
		/// 获取物体在指定相机的屏幕图像大小饱和度
		/// </summary>
		public void ResetSaturationSize(Camera viewCamera)
		{
			UpdateBoundsVertexs();
			LimitVertexs(viewCamera);
			SortVertexs();
			saturationSize = CalculateArea();
		}
		#endif
		/// <summary>
		/// 更新包围盒顶点位置
		/// </summary>
		private void UpdateBoundsVertexs()
		{
			if(boundsVertexs == null || boundsVertexs.Length != 8)
			{
				boundsVertexs = new Vector3[8];
			}
			boundsVertexs[0] = Renderer.bounds.min;
			boundsVertexs[7] = Renderer.bounds.max;
			
			boundsVertexs[1].x = boundsVertexs[2].x = boundsVertexs[3].x = boundsVertexs[0].x;
			boundsVertexs[4].x = boundsVertexs[5].x = boundsVertexs[6].x = boundsVertexs[7].x;
			
			boundsVertexs[1].y = boundsVertexs[4].y = boundsVertexs[5].y = boundsVertexs[0].y;
			boundsVertexs[2].y = boundsVertexs[3].y = boundsVertexs[6].y = boundsVertexs[7].y;
			
			boundsVertexs[2].z = boundsVertexs[4].z = boundsVertexs[6].z = boundsVertexs[0].z;
			boundsVertexs[1].z = boundsVertexs[3].z = boundsVertexs[5].z = boundsVertexs[7].z;
		}
		/// <summary>
		/// 限制包围盒顶点在屏幕内
		/// </summary>
		private void LimitVertexs(Camera viewCamera)
		{
			for(int i = 0; i < 8; ++i)
			{
				boundsVertexs[i] = viewCamera.WorldToScreenPoint(boundsVertexs[i]);
				if(boundsVertexs[i].x < 0)
				{
					boundsVertexs[i].x = 0;
				}
				else if(boundsVertexs[i].x > Screen.width)
				{
					boundsVertexs[i].x = Screen.width;
				}
				if(boundsVertexs[i].y < 0)
				{
					boundsVertexs[i].y = 0;
				}
				else if(boundsVertexs[i].y > Screen.height)
				{
					boundsVertexs[i].y = Screen.height;
				}
			}
		}
		/// <summary>
		/// 将屏幕上的8个点冒泡排序，y从大到小，相同时x从大到小
		/// </summary>
		private void SortVertexs()
		{
			int i, j;
			for(i = 0; i < 7; ++i)
			{
				for(j = i + 1; j < 8; ++j)
				{
					if (boundsVertexs[j].y > boundsVertexs[i].y || 
						(boundsVertexs[j].y == boundsVertexs[i].y && boundsVertexs[j].x > boundsVertexs[i].x))
					{
						(boundsVertexs[i], boundsVertexs[j]) = (boundsVertexs[j], boundsVertexs[i]);
					}
                }
			}
		}
		/// <summary>
		/// 获取粗略梯形面积
		/// </summary>
		private float CalculateArea()
		{
			float topBase = Vector2.Distance(boundsVertexs[0], boundsVertexs[3]);
			float bottomBase = Vector2.Distance(boundsVertexs[4], boundsVertexs[7]);
			// 计算梯形的高度
			float height = (boundsVertexs[0].y - boundsVertexs[4].y + boundsVertexs[3].y - boundsVertexs[7].y) * 0.5f;
			// 计算梯形的面积
			return (topBase + bottomBase) * height * 0.5f;
		}
	}
}
